package com.lyf.boot.modules.monitor.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.lyf.boot.annotation.Log;
import com.lyf.boot.constant.CacheConstant;
import com.lyf.boot.core.model.PageInfo;
import com.lyf.boot.core.model.R;
import com.lyf.boot.enums.BusinessType;
import com.lyf.boot.modules.monitor.entity.dto.ForceLogoutDto;
import com.lyf.boot.modules.monitor.entity.dto.SysUserOnlinePageDto;
import com.lyf.boot.modules.monitor.entity.vo.SysUserOnlineVo;
import com.lyf.boot.utils.RedisUtil;
import com.lyf.boot.utils.StreamUtil;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/** 
 * 在线人员监控
 * @author Luyufan
 * @date 2024/1/10 15:45
 **/
@RestController
@RequestMapping("sysUserOnline")
@AllArgsConstructor
@Slf4j
public class SysUserOnlineController {

    /**
     * 分页获取在线用户
     * @param dto
     * @return
     */
    @SaCheckPermission("monitor:online:list")
    @PostMapping("getSysUserOnlinePage")
    public R<PageInfo<SysUserOnlineVo>> getSysUserOnlinePage(@RequestBody @Valid SysUserOnlinePageDto dto){
        // 获取所有未过期的 token
        List<SysUserOnlineVo> userList = new ArrayList<>();
        List<String> keys = StpUtil.searchTokenValue("", 0, -1, false);
        for (String key : keys) {
            String token = StrUtil.subAfter(key, ":", true);
            if(StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1){
                //过期的跳过
                continue;
            }
            SysUserOnlineVo cacheUser = RedisUtil.getCacheObject(CacheConstant.ONLINE_TOKEN_KEY + token);
            if(cacheUser != null && !BeanUtil.isEmpty(cacheUser)){
                userList.add(cacheUser);
            }
        }
        String username = dto.getUsername();
        String realName = dto.getRealName();
        if (StrUtil.isNotBlank(username) && StrUtil.isNotBlank(realName)){
            userList = StreamUtil.filter(userList, o -> StrUtil.contains(o.getUsername(), username) && StrUtil.contains(o.getRealName(), realName));
        }else if(StrUtil.isNotBlank(username)){
            userList = StreamUtil.filter(userList, o -> StrUtil.contains(o.getUsername(), username));
        }else if(StrUtil.isNotBlank(realName)){
            userList = StreamUtil.filter(userList, o -> StrUtil.contains(o.getRealName(), realName));
        }
        userList = StreamUtil.sorted(userList, Comparator.comparing(SysUserOnlineVo::getLoginTime));
        Collections.reverse(userList);
        userList.removeAll(Collections.singleton(null));
        return R.ok(PageInfo.build(userList, dto.getPageNum(), dto.getPageSize()));
    }

    /**
     * 强退用户
     *
     * @param dto token值
     */
    @SaCheckPermission("monitor:online:forceLogout")
    @Log(module = "在线用户",business = "强退用户", businessType = BusinessType.FORCE)
    @PostMapping("/forceLogout")
    public R<Void> forceLogout(@RequestBody ForceLogoutDto dto) {
        try {
            StpUtil.kickoutByTokenValue(dto.getTokenId());
        } catch (NotLoginException ignored) {
        }
        return R.ok();
    }
}
